import gnu.io.SerialPort;

import java.awt.BorderLayout;
import java.awt.FlowLayout;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.GridLayout;
import javax.swing.JLabel;

import java.awt.Component;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import java.awt.SystemColor;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.sql.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;
import java.util.regex.Pattern;

import javax.swing.border.BevelBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.SoftBevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.SwingConstants;
import java.awt.Color;
import java.awt.Toolkit;
import javax.swing.JCheckBox;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BoxLayout;


/**
 * 
 */

/**
 * @author Toshiharu Ikeda <ikeda.104@gmail.com>
 *
 */
public class AmpPower extends JDialog implements propertyReadWritable, ChangeListener {

	private static final String Title = "AMP Power adjust tool ver1.01 / T.Ikeda@HAKUSAN";  //  @jve:decl-index=0:
	private static final String propertyFile = new String("AMPPower.properties");  //  @jve:decl-index=0:
	private static final long serialVersionUID = 1L;

	private final JPanel contentPanel = new JPanel();
	
	private Object[][] Voltage = null;
	private RxCommTask rxCommTask=null;
	private RxUDPTask rxUDPTask=null;
	private JButton btnStart = null;
	private SerialPort CommPort=null; 
	private Timer rxTimer = null;
	private String commParam = new String("COM4/9600/8/1/0/0");
	private String udpPort= new String("10001");
	
	private Properties config = new Properties();  //  @jve:decl-index=0:
	private int CommMode = 0; // 0: UDP

	private JCheckBox[] CBHighlight=null;   
	public  int Counter=0;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		try {
			AmpPower dialog = new AmpPower();
			dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			dialog.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Create the dialog.
	 * @param ChangeLintener 
	 */
	public AmpPower() {
		final JPanel panel;
		setIconImage(Toolkit.getDefaultToolkit().getImage(AmpPower.class.getResource("/com/sun/java/swing/plaf/windows/icons/Computer.gif")));
		
		File pf = new File(propertyFile);
		loadProp(pf);
  
		setTitle(Title);
		setBounds(100, 100, 706, 504);
		getContentPane().setLayout(new BorderLayout());
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		getContentPane().add(contentPanel, BorderLayout.CENTER);
		CBHighlight = new JCheckBox[8]; 
//		URL imageIconUrl = getClass().getClassLoader().getResource("images/speedometer11x16.png");
//		ImageIcon icon = new ImageIcon(imageIconUrl);
//		setIconImage(icon.getImage());

		
		this.addWindowListener(new java.awt.event.WindowAdapter() {
			public void windowClosing(java.awt.event.WindowEvent e) {
				onExiting();
				System.exit(0);
			}
		});
		contentPanel.setLayout(new BorderLayout(0, 0));

		{
			panel = new JPanel();
			panel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
			panel.setBackground(new Color(230, 230, 250));
			contentPanel.add(panel, BorderLayout.CENTER);
			GridBagLayout gbl_panel = new GridBagLayout();
			gbl_panel.columnWidths = new int[] {80, 100, 100, 100, 100, 100, 100, 0};
			gbl_panel.rowHeights = new int[] {30, 30, 30, 30, 30, 30, 30, 30, 30, 30};
			gbl_panel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
			gbl_panel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
			panel.setLayout(gbl_panel);
			
			String[] RvNumber = new String[] { " ","RV1","RV2"," ","RV3","RV4" };
			for(int i=0;i<6;i++){
				JLabel lblRv = new JLabel(RvNumber[i]);
				lblRv.setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				lblRv.setEnabled(false);
				GridBagConstraints gbc_lblRv = new GridBagConstraints();
				gbc_lblRv.anchor = GridBagConstraints.CENTER;
				gbc_lblRv.insets = new Insets(0, 0, 5, 5);
				gbc_lblRv.gridx = 1+i;
				gbc_lblRv.gridy = 0;
				panel.add(lblRv, gbc_lblRv);
			
			}

			{
				JLabel lblVd = new JLabel("VD1");
				lblVd.setEnabled(false);
				lblVd.setBackground(Color.GRAY);
				lblVd.setFont(new Font("MS UI Gothic", Font.BOLD | Font.ITALIC, 18));
				GridBagConstraints gbc_lblVd = new GridBagConstraints();
				gbc_lblVd.fill = GridBagConstraints.VERTICAL;
				gbc_lblVd.insets = new Insets(0, 0, 5, 5);
				gbc_lblVd.gridx = 1;
				gbc_lblVd.gridy = 1;
				panel.add(lblVd, gbc_lblVd);
			}
			{
				JLabel lblVctl = new JLabel("Vctl1");
				lblVctl.setEnabled(false);
				lblVctl.setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				GridBagConstraints gbc_lblVctl = new GridBagConstraints();
				gbc_lblVctl.insets = new Insets(0, 0, 5, 5);
				gbc_lblVctl.gridx = 2;
				gbc_lblVctl.gridy = 1;
				panel.add(lblVctl, gbc_lblVctl);
			}
			{
				JLabel lblVg = new JLabel("VG1");
				lblVg.setEnabled(false);
				lblVg.setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				GridBagConstraints gbc_lblVg = new GridBagConstraints();
				gbc_lblVg.insets = new Insets(0, 0, 5, 5);
				gbc_lblVg.gridx = 3;
				gbc_lblVg.gridy = 1;
				panel.add(lblVg, gbc_lblVg);
			}
			{
				JLabel lblVd_1 = new JLabel("VD2");
				lblVd_1.setEnabled(false);
				lblVd_1.setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				GridBagConstraints gbc_lblVd_1 = new GridBagConstraints();
				gbc_lblVd_1.insets = new Insets(0, 0, 5, 5);
				gbc_lblVd_1.gridx = 4;
				gbc_lblVd_1.gridy = 1;
				panel.add(lblVd_1, gbc_lblVd_1);
			}
			{
				JLabel lblVctl_1 = new JLabel("Vctl2");
				lblVctl_1.setEnabled(false);
				lblVctl_1.setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				GridBagConstraints gbc_lblVctl_1 = new GridBagConstraints();
				gbc_lblVctl_1.insets = new Insets(0, 0, 5, 5);
				gbc_lblVctl_1.gridx = 5;
				gbc_lblVctl_1.gridy = 1;
				panel.add(lblVctl_1, gbc_lblVctl_1);
			}
			{
				JLabel lblVg_1 = new JLabel("VG2");
				lblVg_1.setEnabled(false);
				lblVg_1.setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				GridBagConstraints gbc_lblVg_1 = new GridBagConstraints();
				gbc_lblVg_1.insets = new Insets(0, 0, 5, 0);
				gbc_lblVg_1.gridx = 6;
				gbc_lblVg_1.gridy = 1;
				panel.add(lblVg_1, gbc_lblVg_1);
			}
			
			for(int i=0;i<8;i++){
				//JLabel label = new JLabel(String.format("%d", i+1));
				//label.setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				GridBagConstraints gbc_label = new GridBagConstraints();
				gbc_label.insets = new Insets(0, 0, 5, 5);
				gbc_label.gridx = 0;
				gbc_label.gridy = 2+i;
				CBHighlight[i] = new JCheckBox(String.format("%d",i+1),false);
				CBHighlight[i].setFont(new Font("MS UI Gothic", Font.BOLD| Font.ITALIC, 18));
				CBHighlight[i].setBackground(panel.getBackground());
				CBHighlight[i].addChangeListener(this);
				
				panel.add(CBHighlight[i], gbc_label);
			}
			
			Voltage = new Component[8][6];
			///JLabel[8][6] Voltage;
			for(int i=0;i<8;i++){
				for(int j=0;j<6;j++){
					Voltage[i][j] = new JLabel("-.--");
					GridBagConstraints gbc_lblVoltage = new GridBagConstraints();
					gbc_lblVoltage.anchor = GridBagConstraints.CENTER;
					gbc_lblVoltage.insets = new Insets(0, 0, 5, 5);
					gbc_lblVoltage.gridx = 1+j;
					gbc_lblVoltage.gridy = 2+i;
					panel.add((Component) Voltage[i][j], gbc_lblVoltage);
					((JComponent) Voltage[i][j]).setFont(new Font("MS UI Gothic", Font.BOLD , 20));
					
				}
			}
			
			
		}
		{
			JPanel buttonPane = new JPanel();
			getContentPane().add(buttonPane, BorderLayout.SOUTH);
			{
				JButton okButton = new JButton("Exit");
				okButton.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						onExiting();
					}
				});
				{	
					String mes;
					if(CommMode==0) mes = "UDP:Port " + udpPort;
					else            mes = commParam;
					btnStart = new JButton("Start " + mes);
					btnStart.setToolTipText("start/stop receiving");
					btnStart.addActionListener(new ActionListener() {
						public void actionPerformed(ActionEvent arg0) {
							String mes;
							if(CommMode==0) mes = "UDP:Port " + udpPort;
							else            mes = commParam;
							if(!isconnect()){
								if(connect()){
									btnStart.setText("Stop  "+ mes);
								}
							}
							else {
								disconnect();
								btnStart.setText("Start "+ mes);
							}
						}
					});
					{
						JButton btnSavevoltage = new JButton("SaveVoltage");
						btnSavevoltage.setToolTipText("save voltage to text file");
						btnSavevoltage.addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent arg0) {
								saveVoltage();
							}
						});
						buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS));
						{
							JPanel panel_1 = new JPanel();
							buttonPane.add(panel_1);
							panel_1.setLayout(new BorderLayout(0, 0));
							{
								JLabel lbImage = new JLabel("");
								panel_1.add(lbImage, BorderLayout.WEST);
								lbImage.setFont(new Font("MS UI Gothic", Font.PLAIN, 20));
								lbImage.setIcon(new ImageIcon(AmpPower.class.getResource("/images/FullSizeRender2.png")));
							}
						}
						buttonPane.add(btnSavevoltage);
					}
					buttonPane.add(btnStart);
				}
				okButton.setActionCommand("OK");
				buttonPane.add(okButton);
				getRootPane().setDefaultButton(okButton);
			}
		}
		{
			JMenuBar menuBar = new JMenuBar();
			setJMenuBar(menuBar);
			{
				JMenu mnFile = new JMenu("Option");
				mnFile.setIcon(new ImageIcon(AmpPower.class.getResource("/images/images/cog_edit.png")));
				menuBar.add(mnFile);
				{
					if(CommMode==0){ 
						JMenuItem mntmCom = new JMenuItem("PORT");
						mntmCom.setIcon(new ImageIcon(AmpPower.class.getResource("/images/images/connect.png")));
						mntmCom.addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent arg0) {
								String para = doUDPSettingDialog(udpPort);
								if(para !=null) udpPort=para;
							}
						});
						mnFile.add(mntmCom);
					}
					else{
						JMenuItem mntmCom = new JMenuItem("COM");
						mntmCom.setIcon(new ImageIcon(AmpPower.class.getResource("/images/images/connect.png")));
						mntmCom.addActionListener(new ActionListener() {
							public void actionPerformed(ActionEvent arg0) {
								String para = doCommDialog(commParam);
								if(para !=null) commParam=para;
							}
						});
						mnFile.add(mntmCom);
					}
					JMenuItem mntmTest = new JMenuItem("Test");
					mntmTest.addActionListener(new ActionListener() {
						public void actionPerformed(ActionEvent arg0) {
							if(CommMode == 0){
								//String dat = new String("@1234 5678 1234 8888 0000 9999 2234 5678 1234 8888 0000 9999 1234 5678 4234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999\r");
								String vdat = String.format("@%d ",Counter++);
								String dat = vdat + new String("2474 14 103 2474 14 105 2474 14 105 2474 14 105 2474 14 105 2474 14 103 2474 14 105 2474 14 105 2474 14 103 2474 14 105 2474 14 105 2474 14 105 2474 14 105 2474 14 103 2474 14 105 2474 14 \n\t");
								
								DatagramSocket socket;
								try {
									socket = new DatagramSocket();
									InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
									int port = Integer.valueOf(udpPort);
									DatagramPacket  packet = new DatagramPacket(dat.getBytes(), dat.getBytes().length, inetAddress,port);
									socket.send(packet);	
									
								} catch (SocketException e) {
									e.printStackTrace();
								} catch (UnknownHostException e) {
									e.printStackTrace();
								} catch (IOException e) {
									e.printStackTrace();
								} 
							}
							else{
								try {
									OutputStream os = CommPort.getOutputStream();
									//String dat = new String("@1234 5678 1234 8888 0000 9999 2234 5678 1234 8888 0000 9999 1234 5678 4234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999 1234 5678 1234 8888 0000 9999\r");
									String dat = new String("@105 2474 14 103 2474 14 105 2474 14 105 2474 14 105 2474 14 105 2474 14 103 2474 14 105 2474 14 105 2474 14 103 2474 14 105 2474 14 105 2474 14 105 2474 14 105 2474 14 103 2474 14 105 2474 14 ");
									os.write(dat.getBytes());
									os.close();
								} catch (IOException e) {
									e.printStackTrace();
								}
							}
						}
					});
					mnFile.add(mntmTest);
				}
			}
		}
	}
	private void saveVoltage()
	{
		Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-hhmmss");
        String strDate = sdf.format(cal.getTime()) + ".voltage.txt";
 		try{
 	 		File file = new File(strDate);
 			  FileWriter filewriter = new FileWriter(file);
 			  for(int i=0;i<8;i++){
 				  String line = (String.format("%d \t ",i+1));
 				  for(int j=0;j<6;j++){
 					 line += ((JLabel)Voltage[i][j]).getText() + " \t";
 				  }
 				  filewriter.write(line + "\n");
 			  }
 			  filewriter.close();
 			}catch(IOException e){
 			  System.out.println(e);
 			}
		
	}
	private void loadProp(File f){
		try {
			InputStream is = new FileInputStream(f);
			config.loadFromXML(is);
			is.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (InvalidPropertiesFormatException e){
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//super.readProperty(config);
		readProperty(config);
		
	}
	/**
	 * 
	 * @param f
	 */
	private void saveProp(File f){
		//super.writeProperty(config);
		writeProperty(config);
		try {
			OutputStream os = new FileOutputStream(f);
			config.storeToXML(os, "This file is AMP Power moitor property file","Shift_JIS");
			os.flush();
			os.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	
	private String doUDPSettingDialog(String param)
	{
		String str = JOptionPane.showInputDialog(this,"UDP Port",param);
		if(str == null) return null;
		return str;
		
	}
	private String doCommDialog(String param){
		SerialCommSettingDialog dlg = new SerialCommSettingDialog(null);
		dlg.setCommParam(param);
		dlg.setLocationRelativeTo(this);
		dlg.setVisible(true);
		if(dlg.exitCode != 1) return null;
		return dlg.getCommParam();
		
	}

	public void OnReceive(byte[] buf)
	{
		System.out.print("buf=" + buf.length + "\n");
		String s = new String(buf);
		int hidx  = s.lastIndexOf('@');
		if(hidx<0 || hidx>=s.length()) return;
		String st = s.substring(hidx+1);
		String[] as = st.split("\\s+");
		System.out.print("Len:" + as.length);
		for(int i=0;i<as.length;i++){
			if(as[i].isEmpty()) continue;
			System.out.print(i + " : " + as[i]+"\n");
			double v = Double.valueOf(as[i]);
			if((i %3)==2) v*=-1;
			((JLabel)Voltage[i / 6][i % 6]).setText(String.format("%1.3f",v/1000));
			
		}
		
	}
	private boolean isconnect()
	{
		if(CommMode==0){
			if(rxUDPTask == null) return false;
		}
		else {
			if( rxCommTask == null) return false;
		}
		return true;
	}
	private boolean connect()
	{
		if(CommMode==0){
			int port = Integer.valueOf(udpPort);
			rxUDPTask = new RxUDPTask(port);
			if(rxUDPTask.socket == null) return false;
			rxTimer = new Timer();
			rxTimer.schedule(rxUDPTask,0,20);
		}
		else{
			rxCommTask = new RxCommTask();
			try {
				CommPort = (new SerialComm()).connect(100,commParam);
			} catch (Exception e) {
				JOptionPane.showMessageDialog(this,"Fail to open\n" + commParam + "\n" + e.getMessage(),"Error",JOptionPane.OK_OPTION);
				return false;
			}
			rxTimer = new Timer();
			rxTimer.schedule(rxCommTask,0,20);
		}
		return true;
	}
	private boolean disconnect(){
		if(CommMode==0){
			if(rxUDPTask != null){
				rxUDPTask.stop();
				rxUDPTask = null;
			}
		}
		else{
			if(rxCommTask != null){
				if(rxTimer != null) rxTimer.purge();
				rxCommTask.stop();
				rxCommTask = null;
			}
		}
		return true;
	}
	private void onExiting(){
		disconnect();
		File pf = new File(propertyFile);
		saveProp(pf);
		dispose();
		return;
	}
	class RxCommTask extends TimerTask {
		byte[] buffer = null;
		int index;
		int counter;
		int maxBufferSize = 500;
		public byte[] Buf = null;
		
		RxCommTask(){
			buffer = new byte[maxBufferSize];
			index=0;
			counter=0;
		}
		public void run(){
			InputStream is;
			int len;
			try {
				if(CommPort==null) return;
				is = CommPort.getInputStream();
				len = is.available();
				for(;len>0;index++,len--){
					if(index>=maxBufferSize ){
						index = 0; 
					}
					int rxc = is.read();
					if(rxc == 0x0a || rxc == 0xd){
						if(index>0){
							Buf = new byte[index];
							for(int k=0;k<index;k++) Buf[k] = buffer[k];
							OnReceive(Buf);
						}
						index = 0;
					}
					else{
						buffer[index] = (byte)rxc;
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		public void stop(){
			if(CommPort!=null) CommPort.close();
			this.cancel();
			return;
		}
	}
	class RxUDPTask extends TimerTask {
		byte[] buffer = null;
		int maxBufferSize = 500;
		public byte[] Buf = null;
		DatagramPacket packet = null;
		public DatagramSocket socket = null;
		//int SERVER_PORT = 10001;
		RxUDPTask(int SERVER_PORT){
			buffer = new byte[maxBufferSize];
			packet = new DatagramPacket(buffer, buffer.length);
			try {
				socket = new DatagramSocket(SERVER_PORT);
			} catch (SocketException e) {
				socket = null;
				packet = null;
				e.printStackTrace();
			}
			
		}
		public void run(){
			try {
				socket.receive(packet);
				int len = packet.getLength();
				byte[] b = new byte[len];
				
				System.arraycopy(packet.getData(), 0, b, 0, len);
				OnReceive(b);
				
			} catch (IOException e1) {
				//e1.printStackTrace();
			}
			
		}
		public void stop(){
			if(socket!=null) socket.close();
			this.cancel();
			return;
		}
	}
	/* (non-Javadoc)
	 * @see propertyReadWritable#readProperty(java.util.Properties)
	 */
	@Override
	public void readProperty(Properties prop) {
	    if(prop==null) return;
	    try{
    		commParam = prop.getProperty("SERIAL/PARAMETER","COM1/9600/8/1/0/0");
    		udpPort = prop.getProperty("UDP/PORT","10001");
	 	    } catch(NumberFormatException e){
	 	    	commParam = new String("COM1/9600/8/1/0/0");
	 	    	udpPort = new String("10001");
	 	    }
	}

	/* (non-Javadoc)
	 * @see propertyReadWritable#writeProperty(java.util.Properties)
	 */
	@Override
	public void writeProperty(Properties prop) {
		if(prop==null) return;
		prop.put("SERIAL/PARAMETER", commParam);
		prop.put("UDP/PORT",udpPort);
		
	}

	/* (non-Javadoc)
	 * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
	 */
	@Override
	public void stateChanged(ChangeEvent arg0) {
		for(int i=0;i<8;i++){
			if(CBHighlight[i].isSelected()){
				for(int j=0;j<6;j++){	
					((JComponent) Voltage[i][j]).setFont(new Font("MS UI Gothic", Font.BOLD , 25));
				}
			}
			else{
				for(int j=0;j<6;j++){
					((JComponent) Voltage[i][j]).setFont(new Font("MS UI Gothic", Font.BOLD , 20));
				}
			}
		}
		
	}
}